
// 17.26

#include "802_1w_2001_procedures.h"
#include "bridge.h"
#include "port.h"
#include "assert.h"

enum
{
	UNDEFINED,
	INIT,
	SEND_RSTP,
	SENDING_RSTP,
	SEND_STP,
	SENDING_STP,
};

// ============================================================================

const char* PortProtocolMigration_802_1w_2001_GetStateName (SM_STATE state)
{
	switch (state)
	{
		case INIT:			return "INIT";
		case SEND_RSTP:		return "SEND_RSTP";
		case SENDING_RSTP:	return "SENDING_RSTP";
		case SEND_STP:		return "SEND_STP";
		case SENDING_STP:	return "SENDING_STP";
		default:			return "(undefined)";
	}
}

// ============================================================================

SM_STATE PortProtocolMigration_802_1w_2001_CheckConditions (BRIDGE* bridge, int givenPort, int givenTree, SM_STATE state)
{
	assert (givenPort != -1);
	assert (givenTree == -1);

	PORT* port = bridge->ports [givenPort];
	
	// ------------------------------------------------------------------------
	// Check global conditions.
	
	if ((!port->portEnabled && !port->initPm) || bridge->BEGIN)
	{
		if (state == INIT)
		{
			// The entry block for this state has been executed already.
			return 0;
		}
		
		return INIT;
	}
	
	// ------------------------------------------------------------------------
	// Check exit conditions from each state.
	
	if (state == INIT)
	{
		if ((bridge->ForceProtocolVersion >= 2) && port->portEnabled)
			return SEND_RSTP;
		
		if ((bridge->ForceProtocolVersion < 2) && port->portEnabled)
			return SEND_STP;
		
		return 0;
	}
	
	if (state == SEND_RSTP)
		return SENDING_RSTP;
	
	if (state == SENDING_RSTP)
	{
		if ((port->mDelayWhile != 0) && (port->rcvdSTP || port->rcvdRSTP))
			return SENDING_RSTP;
		
		if (((port->mDelayWhile == 0) && port->rcvdSTP) || (bridge->ForceProtocolVersion < 2))
			return SEND_STP;
		
		if (port->mcheck)
			return SEND_RSTP;
			
		return 0;
	}
	
	if (state == SEND_STP)
		return SENDING_STP;
	
	if (state == SENDING_STP)
	{
		if ((port->mDelayWhile != 0) && (port->rcvdSTP || port->rcvdRSTP))
			return SENDING_STP;
		
		if (((port->mDelayWhile == 0) && port->rcvdRSTP))
			return SEND_RSTP;
		
		if (port->mcheck)
			return SEND_RSTP;
		
		return 0;
	}
	
	assert (false);
	return 0;
}

// ============================================================================

void PortProtocolMigration_802_1w_2001_InitState (BRIDGE* bridge, int givenPort, int givenTree, SM_STATE state)
{
	assert (givenPort != -1);
	assert (givenTree == -1);

	PORT* port = bridge->ports [givenPort];
	
	if (state == INIT)
	{
		port->initPm = true;
		port->mcheck = false;
	}
	else if (state == SEND_RSTP)
	{
		port->mDelayWhile = bridge->MigrateTime;
		port->mcheck = port->initPm = false;
		port->sendRSTP = true;
	}
	else if (state == SENDING_RSTP)
	{
		port->rcvdRSTP = port->rcvdSTP = false;
	}
	else if (state == SEND_STP)
	{
		port->mDelayWhile = bridge->MigrateTime;
		port->sendRSTP = false;
		port->initPm = false;
	}
	else if (state == SENDING_STP)
	{
		port->rcvdRSTP = port->rcvdSTP = false;
	}
	else
		assert (false);
}
